#include "Texture.h"
#include "Logger.h"
#include "FileSystem.h"
#include "stb_image.h"
#include "Stream.h"
#include "Exception.h"
#include "IContext.h"

NS_B2D_BEGIN

//
// Texture
//
B2D_RESOURCE_IMPL(ITexture,IResource)
B2D_OBJECT_IMPL(Texture,ITexture)

bool ITexture::generateMipmapsDefault = true;

Texture::Texture(void)
	: mWidth(0)
	, mHeight(0)
	, mBorder(0)
	, mHasMipmaps(ITexture::generatesMipmapsDefault())

	, mTextureFormat(TextureFormat::INVALID)
{
}

Texture::~Texture(void)
{

}

bool Texture::hasAlpha(void) const
{
	return mTextureFormat == TextureFormat::RGBA8;
}


void Texture::initialiseWithData(const void* data, size_t width, uint height, TextureFormat format, bool mipmaps)
{
	// Set properties
	mWidth = width;
	mHeight = height;
	mTextureFormat = format;
	mHasMipmaps = mipmaps;
	
	// Do actual work
	initialiseWithDataImpl(data);
}

/*
void Texture::updateSamplerState(void)
{
	if( mSamplerStateDirty == true )
	{
		updateSamplerStateImpl();
		mSamplerStateDirty = false;
	}
}*/


void Texture::load(const StreamPtr& stream)
{
	// Get data stream
	if(!stream) B2D_THROW(Exception::NULL_ALRGUMENT_EXCEPTION,
		"Cant load texture from null stream.");

	// Get data from stream
	stream->open(AccessMode::READ);
	uint dataSize = stream->getSize();
	stbi_uc* data = new stbi_uc[dataSize];
	memset(data, 0, dataSize);
	stream->read(data, dataSize);
	stream->close();
	
	// Load image data via stbi
	int width, height, depth;
	stbi_uc* outputData = stbi_load_from_memory(data, dataSize, &width, &height, &depth, 0);
	SafeDeleteArray(data);

	if( outputData == nullptr )
	{
		B2D_THROW(Exception::GRAPHICS_API_EXCEPTION,
			"Could not load image \""+mName.getString()+"\"");
	}

	TextureFormat format = (depth == 4 ? TextureFormat::RGBA8 : TextureFormat::RGB8);

	initialiseWithData(outputData, width, height, format, true);
	stbi_image_free(outputData); //NOTE - this leaks if initialiseWithData() throws
}

size_t Texture::getSizeEstimate(void) const
{
	// TODO SP
	return 0;
}

NS_B2D_END